#include "Message.h"
#include "jSocket.h"
#include "UserInfo.h"
#include "Session.h"
#include "Contact.h"
#include "Fxion.h"


void Session::Init()
{
	Status = 0;
	hThread = NULL;
	hEvent = CreateEvent(NULL,true,false,NULL);//CreateMutex(NULL,false,NULL);
	I = 1;
	Q = 1; 
}

void Session::Init(UserInfo ui)
{
	Init();
	this->ui = ui;
	I = ui.I;
}

void Session::Begin(AStr Uri, AStr msg)
{
	DstUri = Uri;

	AStr csa = msg.get("CS address=\"",";");
	if (csa.ise()) return ;
	if (Sock.s == -1)
		Sock.Init(csa);

	MsgSent = m.scr(ui.fxno,++ui.I,msg);
	res = Request(MsgSent,m.flag());
	if (!res.include("200 OK")) return ;

	MsgSent = m.sci(ui.fxno,++ui.I,DstUri);
	res = Request(MsgSent,m.flag());
	if (res.include("200 OK"))
	{
		I=ui.I;
		Q=4;
		ThreadRcv();
	}
}

void Session::Response(AStr InviteMsg)
{
	DstUri = InviteMsg.get("F: ","\r\n");
	
	Addr = InviteMsg.get("CS address=\"",";");

	Sock.Init(Addr);
	AStr r = Request(m.ir(InviteMsg,ui.I,ui.Q),"Q: 1 R");
	if (r.include("200 OK"))
	{
		ThreadRcv();
	}
}

/*
#ifdef _WIN32_WCE
extern HRESULT RecvMsg(PCWSTR pwzContent, PCWSTR pwzSenderName = L"Fetion", PCWSTR pwzSenderPhone = TEXT("10000"), LPFILETIME pftDeliveryTime = NULL);
#endif
*/
void Session::M_RTN(AStr msg)
{
	AStr from = msg.get("F: ","\r\n");
	AStr Content = msg.mid("\r\n\r\n");
	Contact* pc = Fxion::GetContact(from);
	if (pc)
	{
#ifdef _WIN32_WCE
		RecvMsg(CA2T(Content,CP_UTF8),pc->name.isne()?CA2T(pc->name,CP_UTF8):L" ",pc->mobileno.isne()?CA2T(pc->mobileno,CP_UTF8):CA2T(pc->fxno,CP_UTF8));
#else
		printf("Name:%s\nMobile:%s\n%s\n\n",*CU2A(pc->name),*CU2A(pc->mobileno),(char*)CU2A(Content));
#endif
	}

	MsgSent = m.mr(msg);
	Sock.Write(MsgSent);
}

void Session::O_RTN(AStr msg)
{
	MsgSent = m.or(msg);
	Sock.Write(MsgSent);
}


void Session::BN(AStr msg)
{
	if (msg.include("deregistered")) 
		Status = 0;
	if (msg.include("UserEntered")) 
		Status++;
	if (msg.include("UserLeft")) 
		Status = 0;
}

void Session::RTN(AStr msg)
{
	if (msg.startwith("O "))
		O_RTN(msg);
	if (msg.startwith("M "))
		M_RTN(msg);
	if (msg.startwith("BN "))
		BN(msg);
}

bool Session::SendMsg(AStr msg)
{
	int i=0;

	while(i++<3)
	{
		MsgSent = m.m(ui.uri,ui.I,++ui.Q,msg);
		res = Request(MsgSent,m.flag());
		if (res.include("200 OK")) 
			return true;
		if (res.include(" 434 "))
		{
			Status = 0;
			break;
		}
		Sleep(2000);
	}
	return false;
}

AStr Session::Request(AStr r, AStr f)
{
	AStr res;
	int i = 0;
	if (hEvent)
		ResetEvent(hEvent);
	
	if (r.isne())
		Sock.Write(r);
	
	while(i++ < 100 && Sock.s != -1)
	{
		res = Sock.Request("");
		if (res.include(f))
			break;
		RTN(res);
		res.clear();
		Sleep(100);
	}
	
	if (hEvent)
		SetEvent(hEvent);
	
	if (res.ise())
		Status = 0;
	return res;
}

bool Session::ThreadRcv()
{
	Status = 1;
	DWORD dwThread;
	hThread = CreateThread(NULL,0,SessionRcv,this,0,&dwThread);
	if (hThread)
	{
		ticks = GetTickCount();
		return true;
	}
	return false;
}


DWORD WINAPI Session::SessionRcv(LPVOID p)
{
	AStr res;

	Session* sr = (Session*)p;
#ifdef _DEBUG
	Debug("Enter SessionRcv Thread: %s \n\n",*sr->DstUri);
#endif
	while(sr->Status)
	{	
		if (sr->hEvent)
			WaitForSingleObject(sr->hEvent,INFINITE);

		res = sr->Sock.Request("");

		if (sr->Sock.s == -1) sr->Status = 0; 

		if (res.isne())
		{
			sr->RTN(res);
		}
		else
		{
			sr->KCB();
		}
		res.clear();
		Sleep(100);
	}
	sr->Status = 0;
	sr->Sock.s = -1;
#ifdef _DEBUG
	Debug("Leave SessionRcv Thread: %s \n\n",*sr->DstUri);
#endif
	return 0;
}
